/**************************************************************************************
*
*	Copyright (C) 2009 Brent Andrew Chua - See LICENSE.txt for more info.
*		
*	Filename	-	String.h
*
*	Description -	String class.
*
*	Comments	-	TODO: We need to implement an iterator.
*					
*	Modification History:
*			Name			   Date					Description
*			CodeSushi	-	10/28/2009	-	Creation of String class
**************************************************************************************/

#ifndef _PULSE_STRING_H_
#define _PULSE_STRING_H_
	
#include "PulseBase.h"

namespace Pulse
{
	class String
	{
	public:

		String( VOID );
		String( const String &str );
		String( const CHAR *pStr );

		~String( VOID );

		const CHAR * GetCString( VOID ) const;
		const UINT GetLength( VOID) const;

		const String & operator = ( const CHAR *pStr );
		const String & operator = ( const String &str );

		const String & operator += ( const String &rhs );
		const String & operator += ( const CHAR *pStr );

		CHAR operator [] ( UINT i ) const;
		CHAR & operator [] ( UINT i );

		/* Friend functions */
		friend const String operator + ( const String &lhs, const String &rhs );
		friend const String operator + ( const String &lhs, const CHAR *rhs );
		friend BOOL operator == ( const String &lhs, const String &rhs );
		friend BOOL operator != ( const String &lhs, const String &rhs );
		friend BOOL operator < ( const String &lhs, const String &rhs );
		friend BOOL operator <= ( const String &lhs, const String &rhs );
		friend BOOL operator > ( const String &lhs, const String &rhs );
		friend BOOL operator >= ( const String &lhs, const String &rhs );

	private:
		
		UINT	m_length;
		UINT	m_bufferLength;
		CHAR	*m_pBuffer;
	};

	/* Inlined Implementations */
	
	PSX_INLINE String::String( VOID ) : m_length( 0 ), m_bufferLength( 0 ), m_pBuffer( 0 )
	{

	}

	PSX_INLINE String::String( const String &str ) : m_length( 0 ), m_bufferLength( 0 ), m_pBuffer( 0 )
	{
		*this = str;
	}

	PSX_INLINE String::String( const CHAR *pStr ) : m_length( 0 ), m_bufferLength( 0 ), m_pBuffer( 0 )
	{
		*this = pStr;
	}

	PSX_INLINE String::~String( VOID )
	{
		if ( m_pBuffer )
			delete [] m_pBuffer;
	}

	PSX_INLINE const CHAR * String::GetCString( VOID ) const
	{
		return m_pBuffer;
	}

	PSX_INLINE const UINT String::GetLength( VOID) const
	{
		return m_length;
	}

	PSX_INLINE const String & String::operator = ( const String &str )
	{
		if ( this == &str )
			return *this;

		return (*this = str.m_pBuffer);
	}

	PSX_INLINE CHAR String::operator [] ( UINT i ) const
	{
		PSX_Assert( ( i >= 0 ) && ( i < m_length ), PSX_String( "Index Out Of Bound." ) );
		return m_pBuffer[i];
	}

	PSX_INLINE CHAR & String::operator [] ( UINT i )
	{
		PSX_Assert( ( i >= 0 ) && ( i < m_length ), PSX_String( "Index Out Of Bound." ) );
		return m_pBuffer[i];
	}

	/* Friend Functions */
	PSX_INLINE const String operator + ( const String &lhs, const String &rhs )
	{
		String newStr( lhs );
		newStr += rhs;
		return newStr;
	}

	PSX_INLINE const String operator + ( const String &lhs, const CHAR *rhs )
	{
		String newStr( lhs );
		newStr += rhs;
		return newStr;
	}

	PSX_INLINE BOOL operator == ( const String &lhs, const String &rhs )
	{
		PSX_Assert( lhs.GetCString() && rhs.GetCString(), PSX_String( "lhs or rhs is invalid." ) );
		return !PSX_StrCmp( lhs.GetCString(), rhs.GetCString() );
	}

	PSX_INLINE BOOL operator != ( const String &lhs, const String &rhs )
	{
		PSX_Assert( lhs.GetCString() && rhs.GetCString(), PSX_String( "lhs or rhs is invalid." ) );
		return PSX_StrCmp( lhs.GetCString(), rhs.GetCString() ) != 0;
	}

	PSX_INLINE BOOL operator < ( const String &lhs, const String &rhs )
	{
		PSX_Assert( lhs.GetCString() && rhs.GetCString(), PSX_String( "lhs or rhs is invalid." ) );
		return ( PSX_StrCmp( lhs.GetCString(), rhs.GetCString() ) < 0 );
	}

	PSX_INLINE BOOL operator <= ( const String &lhs, const String &rhs )
	{
		PSX_Assert( lhs.GetCString() && rhs.GetCString(), PSX_String( "lhs or rhs is invalid." ) );
		return ( PSX_StrCmp( lhs.GetCString(), rhs.GetCString() ) <= 0 );
	}
	PSX_INLINE BOOL operator > ( const String &lhs, const String &rhs )
	{
		PSX_Assert( lhs.GetCString() && rhs.GetCString(), PSX_String( "lhs or rhs is invalid." ) );
		return ( PSX_StrCmp( lhs.GetCString(), rhs.GetCString() ) > 0 );
	}

	PSX_INLINE BOOL operator >= ( const String &lhs, const String &rhs )
	{
		PSX_Assert( lhs.GetCString() && rhs.GetCString(), PSX_String( "lhs or rhs is invalid." ) );
		return ( PSX_StrCmp( lhs.GetCString(), rhs.GetCString() ) >= 0 );
	}
};

#endif _PULSE_STRING_H_